/*
 * Created on 03.apr.2006
 * Created by Tomas
 */
package placing;

import java.util.LinkedList;
import java.util.List;

import junit.framework.TestCase;

import org.junit.Before;
import org.junit.Test;

import people.Group;
import people.Person;
import people.PersonNotFoundException;
import util.Debug;


public class RoomTest extends TestCase {
	Room living, bath, bed, kitchen, garage, cellar;
	Person bob, ted, al;
	Group bundys;

	


	@Before
	protected void setUp() throws Exception {
		living 	= new Room(160, "Living-room");
		bath 	= new Room(169862, "Budoir");
		bed 	= new Room(164, "Bedroom");
		kitchen = new Room(8796, "Kitchen");
		garage 	= new Room(87158);
		cellar 	= new Room(11, "Dankness");
		
		bob 	= new Person(12, "Bob", "Sagett");
		ted 	= new Person(24, "Ted", "Bundy");
		al  	= new Person(31, "Al", "Bundy");
		
		bundys 	= new Group("The Bundys");
		
		bundys.addPerson(ted);
		bundys.addPerson(al);
	}


	@Test
	public void testAddingPlaces() throws PlaceNotFoundException {
		assertTrue(living.getPlaces().isEmpty());
		for (int i = 0; i < 23; i++) {
			living.addPlace();
		}
		assertTrue(!living.getPlaces().isEmpty());
		assertEquals(23, living.getPlaces().size());
		
		if (Debug.ON) {
			System.out.println(living);
		}
		
		living.addPlace(new Place(living, 24));

		assertEquals(true, 23 < living.getPlaces().size());
		
		//adding another place no. 1 should overwrite old place no. 1
		int old = living.getNumPlaces();
		living.addPlace(new Place(living, 1));
		assertEquals(old, living.getNumPlaces());
		
		
		try {
			living.addPlace(new Place(living, -2));
			fail(); //should raise exception
		} catch (PlaceNotFoundException e) {
			// This should happen
		}
	}

	@Test
	public void testFindingFreePlaces() {
		
		assertEquals(0, living.getNumFreePlaces());
		
		try {
			living.getRandomFreePlace();
			fail();
		} catch (PlaceNotFoundException e) {
			// Should happen
		}
		
		living.addPlace();
		
		assertEquals(1, living.getNumFreePlaces());
		
		try {
			assertEquals(living.getID(), living.getRandomFreePlace().getRoomID());
		} catch (PlaceNotFoundException e) {
			// Should not happen now
			fail();
		}
		
		try {
			Place onlyFree = living.getRandomFreePlace();
			onlyFree.assign(bob);
		} catch (PlaceNotFoundException e) {
			// Should not happen
			fail("Place not found");
		} catch (ReservationConflictException e) {
			// not reserved, should not happen
			fail("Place was reserved");
		}
		
		try {
			living.getRandomFreePlace();
			fail();
		} catch (PlaceNotFoundException e) {
			// Only Place in Room is no longer free, should throw exception
		}
		
		assertEquals(0, living.getNumFreePlaces());
		
		living.addPlace();
		
		try {
			Place freePlace = living.getRandomFreePlace();
			freePlace.assign(ted);
		} catch (PlaceNotFoundException e) {
			fail("No free place");
		} catch (ReservationConflictException e) {
			fail("Reservation conflict");
		}
		
	}


	public void testGettingPlaces() {
		/* 
		 * This method leaves the living-room with two places assigned to
		 * Ted and Bob, no other rooms have any places.
		 */
		testFindingFreePlaces(); 
		
		List<Place> placesLiving = living.getPlaces();
		List<Place> placesKitchen = kitchen.getPlaces();
		
		assertFalse(placesLiving.isEmpty());
		assertTrue(placesKitchen.isEmpty());
		
		// Check that the Places in the Living-room are assigned to bob or ted
		for (Place p : placesLiving) {
			try {
				assertTrue((p.getCurrent() == bob) || (p.getCurrent() == ted));
			} catch (PersonNotFoundException e) {
				// All Places are assigned, this should not happen
				fail("No person found on place " + p.getPlaceID());
			} 
		}

	}
	
	/*
	 * It is probably better if the removePlace(int) method is private.
	 * 
	 
  	@Test
	public void testRemovingPlaces() throws PlaceNotFoundException {
		try {
			living.removePlace(1);
			fail("Could remove place where none should be");
		} catch (PlaceNotFoundException e) {
			// This should happen
		}
		
		assertTrue(living.isEmpty());
		living.addPlace();
		assertEquals(1, living.getNumPlaces());
		living.removePlace(1);
		assertEquals(0, living.getNumPlaces());
		assertTrue(living.isEmpty());
		
		Place onePlace = new Place(living, 1);
		Place twoPlace = new Place(living, 2);
		Place threePlace = new Place(living, 3);
		
		living.addPlace(onePlace);
		living.addPlace(twoPlace);
		living.addPlace(threePlace);
		
		assertEquals(3, living.getNumPlaces());
		
		living.removePlace(twoPlace);
		
		assertEquals(2, living.getNumPlaces());
		
		living.removeFreePlace();
		
		assertEquals(1, living.getNumFreePlaces());
		assertEquals(onePlace, living.getFreePlace(ted));
	} */


	public void testReservations() {
//		Debug.ON = true;
		
		//five places in the living-room and kitchen, three in the bedroom
		for (int i = 0; i < 5; i++) {
			living.addPlace();
			kitchen.addPlace();
			if (i < 3) {
				bed.addPlace();
			}
		}
		
		//Reserve bedroom for Bob
		if (Debug.ON) {
			System.out.println("\n-------------------\nBefore reservation:\n");
			System.out.println(living + "\n" + kitchen + "\n" + bed);
		}
		bed.reserveRoom(bob);
		
		
		if (Debug.ON) {
			System.out.println("\n-------------------\nAfter Bob reservation:\n");
			System.out.println(living + "\n" + kitchen + "\n" + bed);
		}
		
		//Reserve Kitchen for the Bundys
		kitchen.reserveRoom(bundys);
		if (Debug.ON) {
			System.out.println("\n-------------------\nAfter Bundy reservation:\n");
			System.out.println(living + "\n" + kitchen + "\n" + bed);
		}
		
		//Check that the reservations worked
		List<Place> bedPlaces = bed.getPlaces();
		for (Place p : bedPlaces) {
			assertTrue(p.isReserved());
		}
		List<Place> kitchenPlaces = kitchen.getPlaces();
		for (Place p : kitchenPlaces) {
			assertTrue(p.isReserved());
		}

		
		try {
			bed.getRandomFreePlace();
		} catch (PlaceNotFoundException e) {
			// There are free places, this should not happen
			fail("No free Places in bedroom");
		}
		
		//Test that the reservations only allow the right Persons
		assertTrue(kitchen.isValid(al));
		assertTrue(kitchen.isValid(ted));
		assertFalse(kitchen.isValid(bob));
		assertTrue(bed.isValid(bob));
		assertFalse(bed.isValid(al));
		
		//Test that the reservations truly stop the right assignations
		try {
			//these should work
			kitchen.getRandomFreePlace().assign(al);
			kitchen.getRandomFreePlace().assign(ted);
			bed.getRandomFreePlace().assign(bob);
		} catch (ReservationConflictException e) {
			fail("Assign failed because of reservation");
		} catch (PlaceNotFoundException e) {
			fail("Assign failed because there were no places");
		}
		
		//these should not work
		try {
			bed.getRandomFreePlace().assign(al);
			fail("Assign did not check for reservation");
		} catch (ReservationConflictException e) {
			// This should happen
		} catch (PlaceNotFoundException e) {
			fail("Assign failed because there were no places");
		}
		
		try {
			bed.getRandomFreePlace().assign(ted);
			fail("Assign did not check for reservation");
		} catch (ReservationConflictException e) {
			// This should happen
		} catch (PlaceNotFoundException e) {
			fail("Assign failed because there were no places");
		}
		
		try {
			kitchen.getRandomFreePlace().assign(bob);
			fail("Assign did not check for reservation");
		} catch (ReservationConflictException e) {
			// This should happen
		} catch (PlaceNotFoundException e) {
			fail("Assign failed because there were no places");
		}
		
		
		
		
		Debug.ON = false;
		
	}
	
	@Test
	public void testSinglePlaceReservations() {
//		Debug.ON = true;
		living.addPlace();
		living.addPlace();
		
		try {
			living.reservePlace(1, bob);
		} catch (PlaceNotFoundException e) {
			fail("Could not find Place 1");
		}
		
		if (Debug.ON) {
			System.out.println(living);
		}
		
		LinkedList<Place> livingPlaces = new LinkedList<Place>(living.getPlaces());
		try {
			assertEquals(livingPlaces.getLast(), living.getFreePlace(ted));
		} catch (PlaceNotFoundException e) {
			fail("No free Places for Ted");
		}
		
		try {
			assertEquals(livingPlaces.getFirst(), living.getFreePlace(bob));
		} catch (PlaceNotFoundException e) {
			fail("No free Places for Bob");
		}
		Debug.ON = false;
	}
	
	@Test
	public void testClearReservations() {
		for (int i = 0; i < 5; i++) {
			kitchen.addPlace();
			living.addPlace();
		}
		
		kitchen.reserveRoom(bundys);
		living.reserveRoom(bob);
		
		try {
			living.getFreePlace(al);
			fail("Al should not go in the livingroom");
		} catch (PlaceNotFoundException e) {
			// This should happen
		}
		
		try {
			kitchen.getFreePlace(bob);
			fail("Bob should not go in the Kitchen");
		} catch (PlaceNotFoundException e) {
			// This should happen
		}
		
		kitchen.clearReservations();
		
		try {
			kitchen.getFreePlace(bob);
		} catch (PlaceNotFoundException e) {
			fail("Bob is now allowed in the Kitchen");
		}
		
	}

}
